package client;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import java.net.*;
import fileServer.FileServerApplication;
import cmm.ConnectionInformation;
import filePackets.*;

public class FileClient extends Client {
	// DEFINES
	private static final String LogFileName = "FileClient.log";
	private static final String ClientString = "Client";
	private static final String ProxyAddress = "localhost";
	private static final short ProxyPort = 4096;
	// private variables
	private static server.Logger LogFile;
	private static ConnectionInformation ProxyConnInfo;
	private static ConnectionInformation ServerConnInfo;
	/**
	 * @param args
	 */
	
	private static void LogEntry(String msg){
		LogFile.AddEntry(ClientString, msg);
	}
	
	/**
	 * This is the main function of the FileClient application
	 * 
	 * @param args command line argumets for the Client
	 * @throws  
	 */
	public static void main(String[] args) {
		
		LogFile = new server.Logger();
	
		try {
			LogFile.OpenLog(LogFileName);
		} catch (FileNotFoundException e) {
			System.out.println("cannot create log file");
			e.printStackTrace();
			return;
		}
		LogEntry("Info - Client started");
				
		if (args.length != 1){
			LogEntry("Error - wrong number of command line parameters");
			return;
		}
		Integer FileNumber;
		try {
			FileNumber = new Integer(args[0]);
		} catch (NumberFormatException e2) {
			e2.printStackTrace();
			LogEntry("Error - first command line argument must be an integer number (FileNumber)");
			return;
		}
				
		try {
			ProxyConnInfo.putIP(InetAddress.getByName(ProxyAddress));
		} catch (UnknownHostException e1) {
			e1.printStackTrace();
			LogEntry("Could not resolve Proxy Address "+ProxyAddress);
			return;
		}
		ProxyConnInfo.putPort(ProxyPort);
				
		try {
			ServerConnInfo = GetServerInfo(ProxyConnInfo);
		} catch (Exception e) {
			e.printStackTrace();
			LogEntry("Error - Communicaiton with Proxy failed !");
			return;
		} 
		LogEntry("Info - obtained connection information for server "+ServerConnInfo.getIP());
		DatagramSocket FromServer;
		try {
			FromServer = new DatagramSocket();
		} catch (SocketException e) {
			LogEntry("Could not create a datagram socket for incoming traffic");
			e.printStackTrace();
			return;
		}
				
		ConnectionInformation MyConnInfo = new ConnectionInformation();
		
		MyConnInfo.putIP(FromServer.getLocalAddress());
		short sh = new Integer(FromServer.getLocalPort()).shortValue();
		MyConnInfo.putPort(sh);
						
		NewSessionPacket NewSessionReq = new NewSessionPacket();
		NewSessionReq.setClientData(MyConnInfo);
		NewSessionReq.setRequestedFile(FileNumber);
		
		DatagramPacket UDPPacket;
		try {
			UDPPacket = new DatagramPacket(NewSessionReq.toByteArray(), NewSessionReq.toByteArray().length, ServerConnInfo.getIP(), ServerConnInfo.getPort());
		} catch (IOException e) {
			LogEntry("error converting client's new session request to byte[]");
			e.printStackTrace();
			return;
		}
		try {
			FromServer.send(UDPPacket);
		} catch (IOException e) {
			LogEntry("error sending new session packet to server");
			e.printStackTrace();
			return;
		}
		FileOutputStream OutFile;
		try {
			OutFile = new FileOutputStream("myfile.out");
		} catch (FileNotFoundException e1) {
			LogEntry("error creating file for output");
			e1.printStackTrace();
			return;
		}
				
		boolean done;
		do{
			DataPacket InData;
			try {
				FromServer.receive(UDPPacket);
			} catch (IOException e) {
				LogEntry("error receiveing data packet from server");
				e.printStackTrace();
				return;
			}
			try {
				InData = new DataPacket(UDPPacket.getData());
			} catch (IOException e) {
				LogEntry("error converting UDP packet's data to DataPacket");
				e.printStackTrace();
				return;
			} catch (ClassNotFoundException e) {
				LogEntry("error converting UDP packet's data to DataPacket");
				e.printStackTrace();
				return;
			}
			LogEntry("Client: Got block number "+InData.getBlockNumber());
			done = (InData.getBlockData().length == 0);
			try {
				OutFile.write(InData.getBlockData());
			} catch (IOException e) {
				LogEntry("Error writing block to file");
				e.printStackTrace();
				return;
			}
						
		}while (!done);
		try {
			OutFile.close();
		} catch (IOException e) {
			LogEntry("Error closing file");
			e.printStackTrace();
			return;
		}
		LogEntry("Client: done receiving file");
		
	}
}
